﻿using LightCAD.Core;
using LightCAD.Core.Elements;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using static LightCAD.Runtime.Constants;

namespace LightCAD.Runtime
{

    [Flags]
    public enum ViewportStatus
    {
        /// <summary>
        /// 无 没有任何其他事务
        /// </summary>
        None = 0,
        /// <summary>
        /// 正在执行某一个action 工作过程中
        /// </summary>
        InAction = 1,
        /// <summary>
        /// 框选
        /// </summary>
        RectSelect = 2,
        /// <summary>
        /// 右键拖拽平移 整个视口对象
        /// </summary>
        RightButtonPan = 4,
        /// <summary>
        /// 拖拽选中对象
        /// </summary>
        DragSelection = 8,
        /// <summary>
        /// 拖拽控制点对象
        /// </summary>
        DragGrip = 16,
        /// <summary>
        /// 粘贴内容的对象
        /// </summary>
        Pasting = 32,
        /// <summary>
        /// 右键菜单对象
        /// </summary>
        ContextMenu = 64,
        /// <summary>
        /// 正在输入命令中
        /// </summary>
        CmdTextInInput = 128
    }
  
    /// <summary>
    /// 视口的运行管理类，调度各类活动及处理无活动状态
    /// </summary>
    public class ViewportRuntime
    {
        public IViewportControl Control { get; set; }
        public DisplayType DisplayType { get; set; }
        public ElementAction ActiveAction { get; set; }
        public ViewportStatus Status { get; set; }

        private ViewportStatus storeStatus;

        internal DocumentRuntime docRt;
        public SnapRuntime SnapRt { get; set; }

        public bool IsRefEditing { get; set; }
        public RefEditingObject RefEditingObject { get; set; }


        internal Matrix3d ScrToDcs;
        internal Matrix3d DcsToScr;

        internal Matrix3d DcsToWcs;
        internal Matrix3d WcsToDcs;

        public Matrix3d WcsToScr;
        public Matrix3d ScrToWcs;

        public Matrix3d UcsToWcs;
        public Matrix3d WcsToUcs;

        public Matrix3d UcsToScr;
        public Matrix3d ScrToUcs;
        private ICreateDrawer createDrawer;
        private ITransformDrawer transformDrawer;
        /// <summary>
        /// 指针按下坐标
        /// </summary>
        public SKPoint PointerPressedPosition { get; set; }
        /// <summary>
        /// 指针移动坐标
        /// </summary>
        public SKPoint PointerMovedPosition { get; set; }
        /// <summary>
        /// 指针释放坐标
        /// </summary>
        public SKPoint PointerReleasedPosition { get; set; }
        /// <summary>
        /// 滚轮触发的指针坐标
        /// </summary>
        public SKPoint PointerWheelPosition { get; set; }


        public LcViewport Viewport { get; private set; }

        public Vector2d PanCenter { get; internal set; }

        public ViewportRenderer Renderer { get; private set; }

        public LcCursorType CursorType { get; set; } = LcCursorType.SelectElement;
        public CursorAddonType CursorAddon { get; set; } = CursorAddonType.None;

        /// <summary>
        /// 当前活动的元素集，用于各类元素操作
        /// </summary>
        public ElementSet ActiveElementSet { get; set; }
        /// <summary>
        /// 当前非活动的元素集，一般情况为空，在位编辑时，为ModelSpace
        /// </summary>
        public ElementSet DeactiveElementSet { get; set; }

        public ICreateDrawer CreateDrawer { get => createDrawer; set => createDrawer = value; }
        public ITransformDrawer TransformDrawer { get => transformDrawer; set => transformDrawer = value; }
        public bool IsCreateDrawing { get; set; }
        public bool IsTransformDrawing { get; set; }
        public IPopupObject HoveredTip { get; set; }



        public ViewportRuntime(DocumentRuntime docRt, LcViewport viewport, IViewportControl control)
        {
            this.docRt = docRt;
            this.Viewport = viewport;
            this.Control = control;
            this.Renderer = new ViewportRenderer(docRt, this);

            // this.Control.DetachEvents(this.OnMouseEvent, this.OnKeyDown,this.OnKeyUp, this.OnSizeChanged, this.OnSkRender);
            this.Control.AttachEvents(this.OnMouseEvent, this.OnKeyDown, this.OnKeyUp, this.OnSizeChanged, this.OnSkRender);

            this.ActiveElementSet = this.docRt.Document.ModelSpace;
            this.DeactiveElementSet = null;

            //this.hoverTimer = new System.Timers.Timer();
            //this.hoverTimer.Interval = HoverDelayTime;
            //this.hoverTimer.Elapsed += HoverTimer_Elapsed;
        }


        public bool CheckStatus(ViewportStatus status)
        {
            if (status == ViewportStatus.None)
                return status == this.Status;
            else
                return (status & this.Status) == status;
        }
        public void SetStatus(ViewportStatus status, bool isClear = true)
        {
            if (isClear)
                this.Status = status;
            else
                this.Status |= status;
        }
        public void RemoveStatus(ViewportStatus status)
        {
            this.Status &= ~status;
        }
        public void ClearStatus()
        {
            this.Status = ViewportStatus.None;
        }
        public void OnSizeChanged(Bounds bounds)
        {
            this.Viewport.Width = bounds.Width;
            this.Viewport.Height = bounds.Height;
            this.Control.ForceRefresh = true;

            ResetCoordMatrix();


            Renderer.ScrScope = bounds.ToSKRect();
            Renderer.WorldScope.Location = new Vector2d(-Renderer.OriginX, -Renderer.OriginY);
            Renderer.WorldScope.Width = Renderer.ScrScope.Width / Renderer.Zoom;
            Renderer.WorldScope.Height = Renderer.ScrScope.Height / Renderer.Zoom;
        }
        private bool isInitCoord;
        public void ResetCoordMatrix()
        {
            var vp = this.Viewport;
            if (!isInitCoord)
            {
                vp.Scale = 0.05;
                isInitCoord = true;
            }

            //从屏幕到中心设备坐标系 相当于平移加镜像
            this.DcsToScr = Matrix3d.Translate(vp.Width / 2, vp.Height / 2) * Matrix3d.Scale(1, -1);
            this.ScrToDcs = this.DcsToScr.Inverse();

            //从设备坐标转换到世界坐标系
            this.WcsToDcs = Matrix3d.Translate(vp.Center.X, vp.Center.Y) * Matrix3d.Scale(vp.Scale);
            this.DcsToWcs = this.WcsToDcs.Inverse();

            //世界坐标系直接到屏幕
            this.WcsToScr = DcsToScr * this.WcsToDcs;
            this.ScrToWcs = this.WcsToScr.Inverse();


            //两次分别的转换等同于一次转换
            //DcsToWcs->ScrToDcs == ScrToWcs

            if (this.Viewport.Ucs.IsIdentity())
            {
                this.WcsToUcs = Matrix3d.Identity;
                this.UcsToWcs = Matrix3d.Identity;
                this.UcsToScr = WcsToScr;
                this.ScrToUcs = ScrToWcs;
            }
            else
            {
                //用户坐标系到世界坐标系
                this.UcsToWcs = this.Viewport.Ucs.Matrix;
                this.WcsToUcs = this.UcsToWcs.Inverse();

                //用户坐标系直接到屏幕
                this.UcsToScr = this.WcsToScr * this.UcsToWcs;
                this.ScrToUcs = this.UcsToScr.Inverse();

                if (this.Viewport.Ucs.IsPlan)
                {
                    //用户坐标系放平，等同于对所有坐标系进行反向旋转
                    var angle = this.Viewport.Ucs.XAxis.Angle();
                    var rtmat = Matrix3d.RotateInRadian(angle, this.Viewport.Ucs.Origin);

                    this.DcsToScr = Matrix3d.Multiply(rtmat, this.DcsToScr);
                    this.ScrToDcs = this.DcsToScr.Inverse();

                    this.WcsToScr = Matrix3d.Multiply(rtmat, this.WcsToScr);
                    this.ScrToWcs = this.WcsToScr.Inverse();

                    this.UcsToScr = Matrix3d.Multiply(rtmat, this.UcsToScr);
                    this.ScrToUcs = this.UcsToScr.Inverse();
                }
            }
        }
        internal virtual void OnMouseEvent(string type, MouseEventRuntime e)
        {
            //如果有Action执行，则由相关Action接管处理
            if (ActiveAction != null) return;

            if (type == "Down") OnMouseDown(e);
            else if (type == "Move") OnMouseMove(e);
            else if (type == "Up") OnMouseUp(e);
            else if (type == "Wheel") OnMouseWheel(e);
            else if (type == "HoverStart") OnMouseHoverStart(e);
            else if (type == "HoverEnd") OnMouseHoverEnd(e);

        }
        public bool IsUcsOpened
        {
            get { return !this.Viewport.Ucs.IsIdentity(); }
        }
        public bool IsUcsPlan
        {
            get { return this.Viewport.Ucs.IsPlan; }
        }

        #region Events
        private void OnMouseDown(MouseEventRuntime e)
        {
            this.PointerPressedPosition = e.Location;
            //TODO:对于右键平移的INaction状态也需要处理
            //if (CheckStatus(ViewportStatus.InAction))
            //{
            //    return;
            //}
            if (CheckStatus(ViewportStatus.None))
            {
                //如果没有前序状态，进行如下判断
                if (e.Button == LcMouseButtons.Left)
                {
                    //控制柄选中检测，如果选中进入拖拽控制点模式
                    var grip = this.HitSelectGrip();
                    if (grip != null)
                    {
                        SetStatus(ViewportStatus.DragGrip);
                        goto Label_End;
                    }

                    //选中/不选中 元素检测，Click为选中，Shift+Click为不选中
                    LcElement hitEle = null;
                    if (e.KeyModifiers == LcKeyModifiers.Shift)
                    {
                        hitEle = this.HitUnselect();
                    }
                    else
                    {
                        //选中元素后，如果重复选中，进入选中拖拽模式
                        bool isFirstSelected = false;
                        hitEle = this.HitSelect(ref isFirstSelected);
                        if (hitEle != null && !isFirstSelected)
                        {
                            OnMouseHoverEnd(e);
                            SetStatus(ViewportStatus.DragSelection);
                            this.docRt.Action.DragSelectionX = 0;
                            this.docRt.Action.DragSelectionY = 0;
                            return;
                        }
                    }
                    //如果没有选中元素，则进入矩形框选模式
                    if (hitEle == null)
                    {
                        SetStatus(ViewportStatus.RectSelect);
                        CursorType = LcCursorType.None;
                    }
                }
                else if (e.Button == LcMouseButtons.Right)
                {
                    //点击右键进入右键平移模式，此模式需要保持当前状态，以确保平移后回到当前状态
                    this.storeStatus = this.Status;//将当前的状态进行保存
                    SetStatus(ViewportStatus.RightButtonPan);
                    this.PanCenter = this.Viewport.Center;
                    this.PointerMovedPosition = e.Location;//清除前序Moved坐标
                }

            }
            else if (CheckStatus(ViewportStatus.CmdTextInInput))
            {
                return;
            }
            else if (CheckStatus(ViewportStatus.DragSelection))
            {
                ClearStatus();
                this.EndDragSelection(e.KeyModifiers == LcKeyModifiers.Control);
            }
            else if (CheckStatus(ViewportStatus.Pasting))
            {
                this.docRt.Action.PasteDone();
                ClearStatus();
            }
            else if (CheckStatus(ViewportStatus.DragGrip))
            {
                //TODO BeginAction代码放在这里不合适
                DocumentManager.CurrentRecorder.BeginAction("DragGrip");
                this.DraggingGripEnd();

                //拖拽控制点结束
                ClearStatus();
                DocumentManager.CurrentRecorder.EndAction();
            }

        Label_End:
            return;
        }

        //#region Hover

        //private SKPoint preHover;
        //private bool isPointerHovering;
        //private System.Timers.Timer hoverTimer;
        //private void HoverTimer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
        //{
        //    hoverTimer.Stop();
        //    this.isPointerHovering = true;
        //    HoverEventStart();
        //}
        private void OnMouseHoverStart(MouseEventRuntime e)
        {
            if (CheckStatus(ViewportStatus.None))
            {
                this.HoverSelect();
            }
        }
        private void OnMouseHoverEnd(MouseEventRuntime e)
        {
            if (CheckStatus(ViewportStatus.None))
            {
                this.HoverUnselect();
            }
        }

        //#endregion

        private void OnMouseMove(MouseEventRuntime e)
        {
            this.PointerMovedPosition = e.Location;
            //TODO:对于右键平移的INaction状态也需要处理
            //if (CheckStatus(ViewportStatus.InAction))
            //{
            //    return;
            //}
            if (CheckStatus(ViewportStatus.Pasting))
            {
                return;
            }

            if (CheckStatus(ViewportStatus.None))
            {

                ////模拟处理悬停事件，停在某点一段时间触发事件，移动光标悬停结束，等待下一次悬停事件
                ////需要位置发生改变才停止Hover事件，因为ToolTip的显示，会导致Move事件的重复触发
                //if (this.isPointerHovering && preHover != this.PointerMovedPosition)
                //{
                //    this.isPointerHovering = false;
                //    HoverEventEnd();
                //}
                //hoverTimer.Stop();
                //hoverTimer.Start();

            }

            if (CheckStatus(ViewportStatus.CmdTextInInput))
            {
                return;
            }
            if (CheckStatus(ViewportStatus.RightButtonPan))
            {
                this.PanViewScope();
            }

            if (CheckStatus(ViewportStatus.RectSelect)
                || CheckStatus(ViewportStatus.RightButtonPan)
                || CheckStatus(ViewportStatus.Pasting))
            {
                return;
            }

            if (CheckStatus(ViewportStatus.DragGrip))
            {

                this.DraggingGrip();

            }
            else if (CheckStatus(ViewportStatus.DragSelection))
            {
                if (e.KeyModifiers == LcKeyModifiers.Control)
                    this.CursorAddon = CursorAddonType.Plus;
                else
                    this.CursorAddon = CursorAddonType.None;

                this.DragSelects();
            }


            //VPort.ShowFloatBlock(this);

            //lblDrawCount.Content = VPort.DrawCounter + "/" + doc.ModelSpace.Elements.Count;

        }

        private void OnMouseUp(MouseEventRuntime e)
        {
            this.PointerReleasedPosition = e.Location;
            //TODO:对于右键平移的INaction状态也需要处理

            if (CheckStatus(ViewportStatus.RectSelect))
            {
                ClearStatus();
                CursorType = LcCursorType.SelectElement;
                this.RectSelects();
            }
            if (CheckStatus(ViewportStatus.CmdTextInInput))
            {
                return;
            }
            if (CheckStatus(ViewportStatus.RightButtonPan))
            {
                SetStatus(this.storeStatus);//平移结束后立即恢复前一个状态
                if (PopupContextMenu())
                {
                    SetStatus(ViewportStatus.ContextMenu);

                }
            }

            if (CheckStatus(ViewportStatus.DragSelection))
            {
                ClearStatus();
                this.EndDragSelection(e.KeyModifiers == LcKeyModifiers.Control);
            }

        }

        private void OnMouseWheel(MouseEventRuntime e)
        {
            if (!CheckStatus(ViewportStatus.DragSelection))
            {
                PointerWheelPosition = e.Location;
                this.ZoomWheel(e.DeltaY);
                //VPort.Zoom = Math.Round(VPort.Zoom, 12);
                Control.ShowInfo("zoom", this.Viewport.Scale);
            }
        }

        internal virtual void OnKeyDown(KeyEventRuntime e)
        {
            if (e.KeyCode == 17)//Ctrl
            {
                if (CheckStatus(ViewportStatus.DragSelection))
                {
                    if (e.KeyModifiers == LcKeyModifiers.Control)
                        this.CursorAddon = CursorAddonType.Plus;
                    else
                        this.CursorAddon = CursorAddonType.None;
                }
            }
            else if (e.KeyCode == 27)//ESC
            {
                this.CancelAll();
            }
            if (!CheckStatus(ViewportStatus.None)) return;

            if (e.KeyModifiers == LcKeyModifiers.Control)
            {
                if (e.KeyCode == 'Z')//Ctrl-Z undo
                {
                    CommandCenter.Instance.Execute("UNDO");
                }
                else if (e.KeyCode == 'Y')//Ctrl-Y redo
                {
                    CommandCenter.Instance.Execute("REDO");
                }
                else if (e.KeyCode == 'C')//Ctrl-C copy
                {
                    CommandCenter.Instance.Execute("COPY");
                }
                else if (e.KeyCode == 'X')//Ctrl-Y cut
                {
                    CommandCenter.Instance.Execute("CUT");
                }
                else if (e.KeyCode == 'V')//Ctrl-V paste
                {
                    CommandCenter.Instance.Execute("PASTE");
                    SetStatus(ViewportStatus.Pasting);
                }
                else if (e.KeyCode == 'S')//Ctrl-S save
                {
                    CommandCenter.Instance.Execute("SAVE");
                }
            }
            else if (e.KeyCode == 46)//Delete
            {
                CommandCenter.Instance.Execute("ERASE");
            }

            //处理在位输入及Esc/Copy，Cut/Paste将启动相应Action
        }

        internal virtual void OnKeyUp(KeyEventRuntime e)
        {
            if (e.KeyCode == 17)//Ctrl
            {
                if (CheckStatus(ViewportStatus.DragSelection))
                {
                    if (e.KeyModifiers == LcKeyModifiers.Control)
                        this.CursorAddon = CursorAddonType.Plus;
                    else
                        this.CursorAddon = CursorAddonType.None;
                }
            }

            if (!CheckStatus(ViewportStatus.None)) return;

        }

        internal virtual void OnSkRender(SKSurface surface)
        {
              
            if (!Control.ForceRefresh && !Control.IsActive) return;
            Control.ForceRefresh = false;

            var canvas = surface.Canvas;

            this.Renderer.Clear(canvas);
            //this.Renderer.DrawGrid(canvas);
            this.Renderer.DrawOriginAxis(canvas);


            if (CheckStatus(ViewportStatus.RectSelect))
            {
                this.Renderer.DrawSelectRect(canvas, this.PointerPressedPosition, this.PointerMovedPosition);
            }

            //处于捕捉状态
            if (this.SnapRt != null)
            {
                if (this.SnapRt.RefPoints.Count > 0)
                {
                    this.Renderer.DrawSnapRefPoints(canvas);
                }
                if(this.SnapRt.RefCurves.Count > 0)
                {
                    this.Renderer.DrawSnapRefCurves(canvas);
                }
                if (this.SnapRt.Current!=null)
                {
                    this.Renderer.DrawSnapPoint(canvas);
                }
            }


            if (!Viewport.Ucs.IsIdentity())
            {
                this.Renderer.DrawUcsIcon(canvas);
            }

            this.Renderer.DrawElements(canvas);
            //Debug.Print("Document: "+this.docRt.Document.FilePath);

            if (this.docRt.Action.SelectedElements.Count > 0 && Control.IsActive)
            {
                this.Renderer.DrawElementGrips(canvas);
            }

            if (this.IsCreateDrawing)
            {
                this.createDrawer.DrawTemp(canvas);
                this.createDrawer.DrawAuxLines(canvas);
            }
            if (this.IsTransformDrawing)
            {
                this.transformDrawer.DrawTrans(canvas);

            }
            if (CheckStatus(ViewportStatus.DragGrip))
            {
                this.Renderer.DrawDragGrip(canvas);
            }
            if (CheckStatus(ViewportStatus.DragSelection))
            {
                this.Renderer.DrawDraggingSelection(canvas);
            }

            if (CheckStatus(ViewportStatus.Pasting))
            {
                this.Renderer.DrawPasteElments(canvas, this.PointerMovedPosition);
            }

            if (Control.IsActive && CursorType != LcCursorType.None)
            {
                this.Renderer.DrawCrossCursor(canvas, CursorType, CursorAddon);
            }

        }

        #endregion




        private void HoverSelect()
        {
            var scrp = PointerMovedPosition.ToVector2d();
            var pw = ConvertScrToWcs(scrp);
            var sizew = SelectBoxSize / this.Viewport.Scale;
            var grip = this.docRt.Action.HoverSelectGrip(pw, sizew);
            //如果没有悬停控制点，则判断有无悬停元素
            if (grip == null)
            {
                var element = this.docRt.Action.HoverSelectElement(docRt.Document.ModelSpace, pw, sizew);
                if (element != null)
                {
                    HoveredTip = this.Control.GetPopupObject("ElementHover");
                    this.Control.Invoke(() =>
                    {
                        var sp = this.Control.PointToScreen(PointerMovedPosition);
                        HoveredTip.Show((int)sp.X + 4, (int)sp.Y + 4);
                    });
                }
            }
        }
        private void HoverUnselect()
        {
            this.docRt.Action.HoverUnselectGrip();

            this.docRt.Action.HoverUnselectElement();
            if (HoveredTip != null)
            {
                HoveredTip.Hide();
            }
        }


        internal void CancelAll()
        {
            docRt.CommandCtrl.WriteInfo(docRt.CommandCtrl.GetPrompt() + "*取消*");
            ClearStatus();
            this.CurrentAction = null;
            this.CursorType = LcCursorType.SelectElement;
            this.CursorAddon = CursorAddonType.None;
            CommandCenter.Instance.InAction = false;
            CancelCurrentAction();
            if (this.docRt.Action.SelectedElements.Count > 0)
            {
                this.docRt.Action.SetSelectsToDragging(false);
                this.docRt.Action.ClearElementGrips();
                this.docRt.Action.ClearSelects();
            }
        }
        internal void EndDragSelection(bool isControlPressed)
        {
            var pre = ConvertScrToWcs(PointerPressedPosition.ToVector2d());
            var cur = ConvertScrToWcs(PointerReleasedPosition.ToVector2d());
            this.docRt.Action.DragSelectionX = cur.X - pre.X;
            this.docRt.Action.DragSelectionY = cur.Y - pre.Y;
            CursorAddon = CursorAddonType.None;
            this.docRt.Action.SetSelectsToDragging(false);
            this.docRt.Action.ClearElementGrips();

            if (isControlPressed)
                this.docRt.Action.DragCopySelection(this.docRt.Action.DragSelectionX, this.docRt.Action.DragSelectionY);
            else
                this.docRt.Action.DragSelection(this.docRt.Action.DragSelectionX, this.docRt.Action.DragSelectionY);


        }


        internal void DragSelects()
        {
            var pre = ConvertScrToWcs(PointerPressedPosition.ToVector2d());
            var mov = ConvertScrToWcs(PointerMovedPosition.ToVector2d());
            this.docRt.Action.DragSelectionX = mov.X - pre.X;
            this.docRt.Action.DragSelectionY = mov.Y - pre.Y;
        }

        private void DraggingGrip()
        {
            var pos = ConvertScrToWcs(PointerMovedPosition.ToVector2d());
            this.docRt.Action.DraggingGrip(pos);
        }
        private void DraggingGripEnd()
        {
            var p = ConvertScrToWcs(PointerPressedPosition.ToVector2d());
            this.docRt.Action.DraggingGripEnd(p);
        }
        public List<LcElement> RectSelects()
        {
            //var fpw = ConvertScrToUcs(PointerPressedPosition.ToVector2d());
            //var spw = ConvertScrToUcs(PointerReleasedPosition.ToVector2d());
            //var selectBox = new Box2d(fpw, spw);
            var fp = PointerPressedPosition.ToVector2d();
            var sp = PointerReleasedPosition.ToVector2d();
            var selectBox = new Box2d(fp, sp);

            var elements = this.docRt.Action.RectSelects(this.docRt.Document.ModelSpace, selectBox, sp.X > fp.X);
            this.docRt.Action.ResetElementGrips(elements);

            return elements;
        }
        /// <summary>
        /// 平移可视范围
        /// </summary>
        public void PanViewScope()
        {
            var vp = this.Viewport;
            var dc_pressed = this.ScrToDcs.MultiplyPoint(this.PointerPressedPosition.ToVector2d());
            var dc_moved = this.ScrToDcs.MultiplyPoint(this.PointerMovedPosition.ToVector2d());
            var scrDx = dc_moved.X - dc_pressed.X;
            var scrDy = dc_moved.Y - dc_pressed.Y;
            if (scrDx == 0 && scrDy == 0) return;

            vp.Center = this.PanCenter + new Vector2d(scrDx, scrDy);
            ResetCoordMatrix();
            //var worldDx = scrDx * vp.Scale;
            //var worldDy = scrDy * zoom;
            //WorldScope.Location.X = PanScope.Location.X - worldDx;
            //WorldScope.Location.Y = PanScope.Location.Y - worldDy;
            //var org = WorldToScr(new Vector2d());
            //OriginX = org.X;
            //OriginY = ScrScope.Height - org.Y;
        }


        /// <summary>
        /// 缩放可视范围
        /// </summary>
        /// <param name="deltaY"></param>
        public void ZoomWheel(double deltaY)
        {
            var vport = this.Viewport;
            if (deltaY < 0)//zoom out 缩小
            {
                GridRatio *= (float)ZoomRatio;
                vport.Scale *= ZoomRatio;
            }
            else //zoom in 放大
            {
                GridRatio /= (float)ZoomRatio;
                vport.Scale /= ZoomRatio;
            }

            if (Math.Round(GridRatio, 6) < 1)
            {
                GridRatio = 5;
            }
            if (Math.Round(GridRatio, 6) > 5)
            {
                GridRatio = 1;
            }

            var zoom = (deltaY > 0) ? (1 / ZoomRatio) : ZoomRatio;
            var wheelp = ScrToWcs.MultiplyPoint(this.PointerWheelPosition.ToVector2d());
            var scaleMatrix = Matrix3d.Scale(zoom, wheelp);//围绕当前点的世界坐标缩放矩阵
            var org = scaleMatrix.MultiplyPoint(new Vector2d());//缩放原点
            vport.Center = WcsToDcs.MultiplyPoint(org);//将原点映射的设备坐标空间
            this.ResetCoordMatrix();
        }
        private bool PopupContextMenu()
        {
            var dx = this.PointerReleasedPosition.X - this.PointerPressedPosition.X;
            var dy = this.PointerReleasedPosition.Y - this.PointerPressedPosition.Y;
            if (Math.Abs(dx) < 2 && Math.Abs(dy) < 2)
            {
                Control.PopupContextMenu(() =>
                {
                    SetStatus(storeStatus);//右键菜单关闭后立即恢复状态
                });
                return true;
            }
            return false;
        }
        private ControlGrip HitSelectGrip()
        {
            var pw = ConvertScrToWcs(PointerPressedPosition.ToVector2d());
            var sizew = (SelectBoxSize) / this.Viewport.Scale;
            var grip = this.docRt.Action.HitSelectGrip(pw, sizew);
            if (grip == null) return null;

            SetStatus(ViewportStatus.DragGrip);
            return grip;

        }
        public LcElement HitUnselect()
        {
            var pw = this.ConvertScrToWcs(PointerPressedPosition.ToVector2d());
            ///var sizew = (SelectBoxSize) / this.Viewport.Scale;
            var sizew = this.ConvertScrToWcs(SelectBoxSize);
            var element = this.docRt.Action.HitUnselect(this.ActiveElementSet, pw, sizew);
            if (element != null) this.docRt.Action.ClearElementGrips(new List<LcElement> { element });
            return element;

        }
        private LcElement HitSelect(ref bool isFirstSelected)
        {
            var pw = this.ConvertScrToWcs(this.PointerPressedPosition.ToVector2d());
            var sizew = Constants.SelectBoxSize / this.Viewport.Scale;
            var result = this.docRt.Action.HitSelect(this.ActiveElementSet, pw, sizew);
            if (result == null) return null;
            if (result.Item2 == true)//首次选中
            {
                this.docRt.Action.ResetElementGrips(new List<LcElement> { result.Item1 });
            }
            isFirstSelected = result.Item2;
            return result.Item1;
        }

        internal void CommandExecute(LcCommand command)
        {
            //if (command.Name.ToUpper() == "OPENUCS")
            //{
            //    this.Viewport.Ucs.Set(new Vector2d(100, 100), new Vector2d(1, 1).Normalized, new Vector2d(-1, 1).Normalized);
            //}
            //else
            if (command.Name.ToUpper() == "CLOSEUCS")
            {
                this.Viewport.Ucs.SetIdentity();
            }
            else
            if (command.Name.ToUpper() == "PLANUCS")
            {
                this.Viewport.Ucs.IsPlan = true;
            }
            else if (command.Name.ToUpper() == "NORMALUCS")
            {
                this.Viewport.Ucs.IsPlan = false;
            }
            ResetCoordMatrix();
        }


        public Vector2d ConvertScrToDcs(Vector2d p) { return ScrToDcs.MultiplyPoint(p); }
        public Vector2d ConvertDcsToScr(Vector2d p) { return DcsToScr.MultiplyPoint(p); }
        public Vector2d ConvertDcsToWcs(Vector2d p) { return DcsToWcs.MultiplyPoint(p); }
        public Vector2d ConvertWcsToDcs(Vector2d p) { return WcsToDcs.MultiplyPoint(p); }
        public Vector2d ConvertWcsToScr(Vector2d p) { return WcsToScr.MultiplyPoint(p); }
        public Vector2d ConvertScrToWcs(Vector2d p) { return ScrToWcs.MultiplyPoint(p); }
        public Vector2d ConvertUcsToWcs(Vector2d p) { return UcsToWcs.MultiplyPoint(p); }
        public Vector2d ConvertWcsToUcs(Vector2d p) { return WcsToUcs.MultiplyPoint(p); }
        public Vector2d ConvertUcsToScr(Vector2d p) { return UcsToScr.MultiplyPoint(p); }
        public Vector2d ConvertScrToUcs(Vector2d p) { return ScrToUcs.MultiplyPoint(p); }

        public double ConvertWcsToScr(double length)
        {
            return length * this.Viewport.Scale;
        }
        public double ConvertScrToWcs(double length)
        {
            return length / this.Viewport.Scale;
        }
        public ElementAction CurrentAction { get; set; }
        public void CancelCurrentAction()
        {
            if (CurrentAction != null)
            {
                CurrentAction.Cancel();
            }

            if (CheckStatus(ViewportStatus.DragSelection))
            {
                ClearStatus();
                this.docRt.Action.SetSelectsToDragging(false);
            }
            if (CheckStatus(ViewportStatus.DragGrip))
            {
                ClearStatus();
            }
            else
            {
                this.docRt.Action.ClearSelects();
            }
        }

        public void SetCreateDrawer(ICreateDrawer drawer)
        {
            if (drawer == null)
            {
                this.IsCreateDrawing = false;
                this.CreateDrawer = null;
            }
            else
            {
                this.IsCreateDrawing = true;
                this.CreateDrawer = drawer;
            }
        }
        public void SetTransformDrawer(ITransformDrawer drawer)
        {
            if (drawer == null)
            {
                this.IsTransformDrawing = false;
                this.transformDrawer = null;
            }
            else
            {
                this.IsTransformDrawing = true;
                this.transformDrawer = drawer;
            }
        }

        public void StartRefEditing()
        {
            this.ActiveElementSet = this.RefEditingObject;
            this.DeactiveElementSet = this.docRt.Document.ModelSpace;
            this.IsRefEditing = true;
        }
        public void CloseRefEditing()
        {
            this.ActiveElementSet = this.docRt.Document.ModelSpace;
            this.RefEditingObject.SyncElements();
            this.RefEditingObject.Dispose();
            this.RefEditingObject = null;
            this.DeactiveElementSet = null;
            this.IsRefEditing = false;

        }

        public Polygon2d GetBoundsPolygon()
        {
            LcViewport vp = this.Viewport;
            Vector2d p0 = this.ScrToWcs.MultiplyPoint(Vector2d.Zero);
            Vector2d p1 = this.ScrToWcs.MultiplyPoint(new Vector2d(0, vp.Height));
            Vector2d p2 = this.ScrToWcs.MultiplyPoint(new Vector2d(vp.Width, vp.Height));
            Vector2d p3 = this.ScrToWcs.MultiplyPoint(new Vector2d(vp.Width, 0));
            return new Polygon2d { Points = new Vector2d[] { p0, p1, p2, p3 } };
        }
     
        internal List<LcElement> GetElementsInBounds(CancellationTokenSource cts=null)
        {
            var bpoly = this.GetBoundsPolygon();
            var bbox = bpoly.BoundingBox;
            var elements = new List<LcElement>();
            foreach(var ele in this.docRt.Document.ModelSpace.Elements)
            {
                if (cts!=null && cts.IsCancellationRequested) return elements;
                if (ele.BoundingBox.IntersectWith(bbox))
                {
                    elements.Add(ele);
                }
            }
            return elements;
        }

        public double GetSnapMaxDistance()
        {
            return this.ConvertScrToWcs(SnapSettings.MaxDistance);
        }
    }
}
 